李守中

FRP 端口映射配置注释

Table of Contents

1. 踩坑

1.1. 非默认端口访问需要全限定域名

给 web 服务做转发,比如从内网 443 端口转发到外网 10443 端口,在外网访问时要加上协议。

直接访问 <ip>:10443 浏览器会把请求解析为 http://<ip>:10443 使用 https 协议需要写 https://<ip>:10443 显式指定。

2. 服务端

放在公网机器上,比如阿里云服务器这种有固定 IP 的。

2.1. frp 服务端配置

下面是一个服务端配置文件的例子:

# 下面这句开头必须要有,表示配置的开始
[common]

# frp 服务端端口(必须)
bind_port = <port>

# frp 服务端密码(必须)
token = <passwd-token>

# 认证超时时间,由于时间戳会被用于加密认证,防止报文劫持后被他人利用
# 因此服务端与客户端所在机器的时间差不能超过这个时间(秒)
# 默认为900秒,即15分钟,如果设置成0就不会对报文时间戳进行超时验证
authentication_timeout = 900

# 仪表盘端口,只有设置了才能使用仪表盘(即后台)
dashboard_port = 7500

# 仪表盘访问的用户名密码,如果不设置,则默认都是 admin
# 注意和 token 区分开。token 用于客户端与服务端通信
# dashboard_pwd 用于登录 web 后台
dashboard_user = <uname>
dashboard_pwd = <passwd-uname>

# 如果想要用 frp 穿透访问内网中的网站(例如路由器设置页面)
# 则必须要设置以下两个监听端口,不设置则不会开启这项功能
vhost_http_port = 10080
vhost_https_port = 10443

# 此设置需要配合客户端设置,仅在穿透到内网中的 http 或 https 时有用(可选)
# 假设此项设置为 example.com,客户端配置 http 时将 subdomain 字段设置为 test
# 在将 test.example.com 通过 DNS 解析到服务端 IP 后
# 可以使用此域名来访问客户端指定的 http
subdomain_host = lishouzhong.top

2.2. nginx 转发 frp 流量以避免手动输入端口号

给一个自用的例子以供参考:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {
    include         /etc/nginx/mime.types;
    include         /etc/nginx/conf.d/*.conf;
    include         /etc/nginx/sites-enabled/*;
    default_type    application/octet-stream;

    log_format      main    '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for" $upstream_cache_status';

    access_log      /var/log/nginx/access.log    main;
    error_log       /var/log/nginx/error.log;

    sendfile                on;
    tcp_nopush              on;
    tcp_nodelay             on;
    keepalive_timeout       65;
    types_hash_max_size     4096;

    resolver 8.8.8.8 8.8.4.4 valid=30s;

    # gzip
    gzip                on;
    gzip_buffers        16 8K;
    gzip_comp_level     6;
    gzip_min_length     1k;
    gzip_types          *;
    gzip_disable        "MSIE [1-6]\."; # ie6 and previous version do not suport gzip
    gzip_vary           on;

    proxy_cache_path    /var/lib/nginx/cache levels=1:2 keys_zone=my_cache:30m
                        max_size=2g inactive=3d use_temp_path=off
                        loader_threshold=300 loader_files=200;

    # ssl config
    ssl_certificate         </path/to/fullchain.pem>;
    ssl_certificate_key     </path/to/privkey.pem>;
    ssl_session_timeout     1d;
    ssl_session_cache       shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets     off;
    ssl_stapling            on; # open OCSP
    ssl_stapling_verify     on; # open OCSP verify

    # TLS version
    ssl_protocols           TLSv1.2 TLSv1.3;
    ssl_ciphers             ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    # ssl_prefer_server_ciphers   OFF; # default OFF

    ssl_trusted_certificate </path/to/fullchain.pem>;

    # WebSocket upgrade
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    # http to https
    server {
        listen                  80;
        listen                  [::]:80;
        server_name             .lishouzhong.top;

        location / {
            return 301          https://$host$request_uri;
        }
    }

    # frp admin
    server {
        listen              443 ssl http2;
        listen              [::]:443 ssl http2;
        server_name         frpdashboard.lishouzhong.top;

        location / {
            proxy_pass      http://127.0.0.1:7500;
        }
    }

    # frp http proxy psss
    server{
        listen                      443 ssl http2;
        server_name                 ~.*frp\.lishouzhong\.top$;

        location / {
            proxy_pass              http://127.0.0.1:10080;
            proxy_ssl_server_name   on;
            proxy_set_header        Host $host;
            # webwocket
            proxy_http_version      1.1;
            proxy_set_header        Upgrade $http_upgrade;
            proxy_set_header        Connection $connection_upgrade;
            proxy_read_timeout      300s;
            proxy_send_timeout      300s;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }

    # frp https proxy pass
    server{
        listen                      443 ssl http2 ;
        server_name                 ~.*frps\.lishouzhong\.top$;

        location / {
            proxy_pass              https://$host:10443;
            proxy_ssl_server_name   on;
            proxy_set_header        Host $host;
            # webwocket
            proxy_http_version      1.1;
            proxy_set_header        Upgrade $http_upgrade;
            proxy_set_header        Connection $connection_upgrade;
            proxy_read_timeout      300s;
            proxy_send_timeout      300s;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
}

3. 客户端配置

放在内网机器上,下面是一个客户端配置文件的例子:

# 表示配置开始
[common]
# frp 服务端地址,ip 或域名二选一
server_addr = <example.com> | <ip>
# frp 服务端端口,即填写服务端配置中的 bind_port
server_port = 7000
# 填写 frp 服务端密码
token = <passwd-token>

# 自定义一个配置名称放在开头,格式为 [<name>]
[rpi_ssh]
# 连接类型,填 tcp 或 udp
type = tcp

# 本地ip,填内网机器的ip
# 如果是转发到frp客户端所在本机 ( 比如路由器 ) 则填 127.0.0.1
local_ip = 192.168.1.30
# 内网机器的端口,比如 ssh 端口是 22
local_port = 22

# 是否加密客户端与服务端之间的通信,默认是 false
use_encryption = false
# 是否压缩客户端与服务端之间的通信,默认是 false
# 压缩可以节省流量,但需要消耗 CPU 资源
# 加密也会消耗 CPU 资源,但是不大
use_compression = true

# frp 服务端的远程监听端口
# 即访问服务端 server_ip:remote_port 相当于访问客户端 local_ip:local_port
# 填 0 会随机分配一个端口
remote_port = 6001

# 转发 windows rdp 端口的配置样例
# [28100_rdp]
# type = tcp
# local_ip = 192.168.2.19
# local_port = 3389
# remote_port = 7190
# use_encryption = false
# use_compression = true



[router_web]
# 连接类型,填 http 或 https
type = http

local_ip = 192.168.1.2
local_port = 80

# http 可以考虑加密和压缩一下
use_encryption = true
use_compression = true

# 自定义访问网站的用户名和密码,如果不定义的话谁都可以访问,会不安全
# 有些路由器如果从内部访问web是不需要用户名密码的,因此需要在这里加一层密码保护
# 如果你发现不加这个密码保护,路由器配置页面原本的用户认证能正常生效的话,可以不加
# only for http, not https.
#http_user = admin
#http_pwd = admin

# 在服务端配置了 subdomain_host = example.com
# 假设这里我们填 web01,那么 DNS 将  解析到服务端ip后
# 就可以使用 web01.example.com:vhost_http_port 来访问内网的 http
# 这个域名的作用是用来区分不同的 http,可以配置多个这样的内网 http
subdomain = ros

# 自定义域名,这个不同于 subdomain,你可以设置与 subdomain_host 无关的其他域名
# subdomain 与 custom_domains 中至少有一个必须要设置
#custom_domains = web02.yourdomain.com

# 匹配路径,可以设置多个,用逗号分隔,比如 locations 配置如下,
# 那么所有 http://xxx/abc 和 http://xxx/def 都会被转发到 http://xxx/
# 如果不需要这个功能可以不写这项,就直接该怎么访问就怎么访问
#locations = /abc,/def

# 重写 host header,相当于反向代理中的“发送域名”
# 如果设置了,转发 http 时,请求中的 host 会被替换成这个
# 一般情况下不需要用到这个,可以不写这项
#host_header_rewrite = dev.yourdomain.com


Last Update: 2023-05-18 Thu 11:01

Generated by: Emacs 28.2 (Org mode 9.5.5)   Contact: [email protected]

若正文中无特殊说明,本站内容遵循: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议